package cn.slipi.core.handler;

import cn.slipi.common.constants.Constants;
import cn.slipi.common.constants.RedisConstants;
import cn.slipi.common.entity.RequestLog;
import cn.slipi.common.exception.InternalException;
import cn.slipi.common.response.Response;
import cn.slipi.common.utils.cache.redis.RedisClient;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

/**
 * GlobalErrorWebExceptionHandler
 */
public class GlobalErrorWebExceptionHandler extends DefaultErrorWebExceptionHandler {

    @Autowired
    private RedisClient redisClient;

    private static final Logger LOGGER = LoggerFactory.getLogger(GlobalErrorWebExceptionHandler.class);

    public GlobalErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ErrorProperties errorProperties, ApplicationContext applicationContext) {
        super(errorAttributes, resourceProperties, errorProperties, applicationContext);
    }

    @Override
    protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
        RequestLog requestLog = (RequestLog) request.exchange().getAttributes().get(Constants.REQUEST_LOG);

        Throwable error = super.getError(request);
        int code = HttpStatus.INTERNAL_SERVER_ERROR.value();
        String message = HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();

        if (error instanceof InternalException) {
            code = ((InternalException) error).getCode();
            message = ((InternalException) error).getMsg();
        }

        requestLog.setException(message);
        requestLog.setEndTimestamp(System.currentTimeMillis());

        LOGGER.info(JSONObject.toJSONString(requestLog));
        this.redisClient.lPush(RedisConstants.REQUEST_LOG, JSONObject.toJSONString(requestLog));

        HttpStatus errorStatus = HttpStatus.INTERNAL_SERVER_ERROR;
        Response errorResponse = new Response(code, message);
        return ServerResponse.status(errorStatus)
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .body(BodyInserters.fromObject(errorResponse))
                .doOnNext((response) -> {
                    LOGGER.error("-----------error-----------");
                });
    }
}
